package cn.lingyangwl.framework.data.mate.fieldbind.inter;

import cn.lingyangwl.framework.data.mate.fieldbind.model.DictType;
import cn.lingyangwl.framework.data.mate.fieldbind.model.FieldBindAnnotationData;
import cn.lingyangwl.framework.tool.core.StringUtils;
import cn.lingyangwl.framework.tool.core.exception.Assert;
import cn.lingyangwl.framework.tool.core.reflection.MetaObject;
import cn.hutool.core.util.StrUtil;

import java.lang.annotation.Annotation;
import java.util.List;
import java.util.function.Function;

/**
 * @author shenguangyang
 */
public interface IDataBind<T> {
    /**
     * 通过对象中所有字典type获取每个type对应的code数据集
     *
     * @param dictTypes 字典类型集合, 所有对象同一个字典类型会被转成一个 {@link DictType}对象的,
     *                  同时内部也对注解所在的字段值进行了去重
     * @return types对应的类型集合, 一般情况下会返回一个map集合, key = type, value = valueOfType(或者集合)
     */
    default T getCodesOfTypes(List<DictType> dictTypes) {
        return null;
    }

    /**
     * 设置元数据对象<br>
     * 每个对象的属性都会调用一次, 比如需要处理一个对象, 其中有10个字段需要进行字段绑定操作, 那么就会被调用10次
     *
     * @param metaObject     处理的对象元数据
     * @param codesOfTypes   对象中所有字典type对应的字典code数据集, 来自 {@link #getCodesOfTypes(List)} 返回结果
     * @param fieldValue     注解所在字段的值
     * @param annotationData 当前处理的字段上自定义的字段绑定注解数据, 来自
     *                       {@link IFieldBindAnnotationDataGetter#initFieldBindAnnotation(Annotation)} (Annotation)} ()}
     *                       方法的返回值
     */
    void setMetaObject(MetaObject metaObject, T codesOfTypes, Object fieldValue,
                       FieldBindAnnotationData annotationData);

    /**
     * 组装目标字段值
     * <p>
     * 需要实现 {@link #getCodesOfTypes(List)} 方法
     * </p>
     *
     * @param fieldValue           字典字段值, eg1: a,b,c  ; eg2: a
     * @param annotationData       字典字段标注的注解信息
     * @param getTargetValueByCode 通过code获取目标字段值 <br/>
     *                             <strong>in:</strong> 字典字段值(如果字段值用分隔符分割了多个code, 这里会进行切分并调用当前方法获取每个code对应的值) <br/>
     *                             <strong>out:</strong> 目标字段值(code对应的值)
     * @return 目标字段值
     */
    default Object assemblyTargetFieldValue(Object fieldValue, FieldBindAnnotationData annotationData,
                                            Function<Object, Object> getTargetValueByCode) {
        Assert.notNull(getTargetValueByCode, "请实现 getTargetValueByCode function");
        String delimiter = annotationData.getDelimiter();
        String annoTargetDelimiter = annotationData.getTargetDelimiter();
        String targetDelimiter = StringUtils.isEmpty(annoTargetDelimiter) ? delimiter : annoTargetDelimiter;
        if ((fieldValue instanceof String) && StringUtils.isNotEmpty(delimiter)) {
            List<String> dictFieldValues = StrUtil.split((String) fieldValue, delimiter);
            StringBuilder targetValue = new StringBuilder();
            for (int i = 0; i < dictFieldValues.size(); i++) {
                Object v = getTargetValueByCode.apply(dictFieldValues.get(i));
                targetValue.append(v);
                if (i < dictFieldValues.size() - 1) {
                    targetValue.append(targetDelimiter);
                }
            }
            return targetValue.toString();
        }
        return getTargetValueByCode.apply(fieldValue);
    }
}
